package com.xneure.utils.cns.identity;

import java.util.Calendar;
import com.xneure.utils.ExtProperties;
import com.xneure.utils.NumUtil;

public class CheckIdCard {
	private final static char[] VERIFY_CODE = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' }; // 18位身份证中最后一位校验码
	private final static int[] VERIFY_CODE_WEIGHT = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };// 18位身份证中，各个数字的生成校验码时的权值
	private static ExtProperties prop;

	public static String getProvinceCity(String idCode) {
		if (null == prop) {
			prop = ExtProperties.readerPropertie("/cartcity.properties");
		}
		idCode = contertToNewCardNumber(idCode);
		return prop.getValue(idCode.substring(0, 6));
	}

	public static int getAge(String idCode) {
		idCode = contertToNewCardNumber(idCode);
		int iAge = 0;
		String year = idCode.substring(6, 10);
		Calendar cal = Calendar.getInstance();
		int iCurrYear = cal.get(Calendar.YEAR);
		iAge = iCurrYear - Integer.valueOf(year);
		return iAge;
	}

	public static Sex getSex(String idCode) {
		idCode = contertToNewCardNumber(idCode);
		return NumUtil.isEven(Integer.valueOf(idCode.substring(16, 17))) ? Sex.woman : Sex.man;
	}

	/**
	 * 把15位身份证号码转换到18位身份证号码<br>
	 * 15位身份证号码与18位身份证号码的区别为：<br>
	 * 1、15位身份证号码中，"出生年份"字段是2位，转换时需要补入"19"，表示20世纪<br>
	 * 2、15位身份证无最后一位校验码。18位身份证中，校验码根据根据前17位生成
	 * 
	 * @param cardNumber
	 * @return
	 */
	private static String contertToNewCardNumber(String oldCardNumber) {
		if (oldCardNumber.length() < 18) {
			StringBuilder buf = new StringBuilder(18);
			buf.append(oldCardNumber.substring(0, 6));
			buf.append("19");
			buf.append(oldCardNumber.substring(6));
			buf.append(calculateVerifyCode(buf));
			return buf.toString();
		} else {
			return oldCardNumber;
		}
	}

	/**
	 * 校验码（第十八位数）：
	 * 
	 * 十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0...16 ，先对前17位数字的权求和；
	 * Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4
	 * 2; 计算模 Y = mod(S, 11)< 通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9
	 * 8 7 6 5 4 3 2
	 * 
	 * @param cardNumber
	 * @return
	 */
	public static char calculateVerifyCode(CharSequence cardNumber) {
		int sum = 0;
		for (int i = 0; i < 17; i++) {
			char ch = cardNumber.charAt(i);
			sum += ((int) (ch - '0')) * VERIFY_CODE_WEIGHT[i];
		}
		return VERIFY_CODE[sum % 11];
	}

	public static boolean verifyIdCard(String cardNumber) {
		String idCard = contertToNewCardNumber(cardNumber);
		return idCard.charAt(idCard.length() - 1) == calculateVerifyCode(idCard);
	}
}
